#include "bplustree.h"
#include "indexrecord.h"

void BPlusTree:: SetIndexRecord ( IndexRecord & _ir, char *keyVal, int _pointer )
{
	assert(m_oKeyType);
	
	switch( m_oKeyType )
	{
		case Int:
		{
			_ir.Load(keyVal, sizeof(int), _pointer);
		}
		case Double:
		{
			_ir.Load(keyVal, sizeof(double), _pointer);
		}
		case String:
		{
			_ir.Load(keyVal, strlen(keyVal), _pointer);
		}
		default:
			cout<<"default:"<<__LINE__<<endl;
			break;
	}
}


void BPlusTree:: FirstInsert (char *keyVal, int pageID)
{
	assert(m_oKeyType);
	
	IndexRecord inLeaf;
	IndexRecord inRoot;
	
	SetIndexRecord (inRoot, keyVal, 1);
	SetIndexRecord (inLeaf, keyVal, pageID);
		
	//This is the basic case
	// TODO change append to return the number of bytes written
	
	m_lPageList[m_iRootLocation].Append( inRoot );
	m_lPageList[m_iRootLocation+1].Append( inLeaf );
		
}

void BPlusTree:: Insert(char *keyVal, int pageID)
{
	//The insert algorithm for B+ Trees -----------------------------
	// Leaf Page = LP
	// Index Page = IP
	// 0 equals empty not full, 1 = full page
	
	// case #1
	// if (LP = 0, IP = 0)
	// Place the record in sorted position in the appropriate leaf page
	
	// case #2
	//else if (LP = 1, IP = 0)
		//1. Split the leaf page
		//2. Place Middle Key in the index page in sorted order.
		//3. Left leaf page contains records with keys below the middle key.
		//Right leaf page contains records with keys equal to or greater than
		//the middle key.
	
	// case #3
	//else if(LP = 1, IP = 0)
		//1. Split the leaf page.
		//2. Records with keys < middle key go to the left leaf page.
		//3. Records with keys >= middle key go to the right leaf page.
		//4. Split the index page.
		//5. Keys < middle key go to the left index page.
		//6. Keys > middle key go to the right index page.
		//7. The middle key goes to the next (higher level) index.
		//IF the next level index page is full, continue splitting the index
		//pages.
	
}

void BPlusTree:: IndexRecursive(char *keyVal, int pageID, int currHeight, int currentPageNo)
{
	if(currHeight == 0) // We are at a leaf
	{
		IndexRecord ir;
		SetIndexRecord( ir, keyVal, pageID );
		m_lPageList[currentPageNo].Append( ir );
		
	}
	else	// We are not at a leaf
	{
		IndexRecord ir;
		Attribute at;
		
		Page p = m_lPageList[currentPageNo];
		ir.GetKey(at);
		
		bool path_taken = false;
		while(p.GetFirst( ir ) && !path_taken)
		{
			
			int i = ir.Compare (at, at, m_oKeyType);
			if( i <= 0 )
			{
				path_taken = true;
				IndexRecursive(keyVal, pageID, currHeight-1,  ir.GetPointer());
			}
		}
				
	}
}


BPlusTree:: BPlusTree ()
{	
	m_iHeight = 0;
	m_iNumPages = 0;
	m_iRootLocation = -1;
}

BPlusTree:: BPlusTree (Type _type)
{
	m_iHeight = 2;
	m_iNumPages = 2;
	m_iRootLocation = 0;
	
	//Create root record
	IndexRecord root;
	
	switch (_type)
	{
		case Int:
		{
			char buf[ sizeof(int)];
			int neginf = -32767;
			sprintf( buf, "%d", neginf );
			root.Load( buf, sizeof(int), 1);
			break;
		}
		case Double:
		{
			char buf[ sizeof(double)];
			double neginf = -1e309;
			sprintf( buf, "%f", neginf );
			root.Load( buf, sizeof(double), 1);
			break;
		}
		case String:
		{
			char* buf = NULL;
			root.Load( buf, sizeof(char*), 1);
			break;
		}
		default:
			cout<<"default:"<<__LINE__<<endl;
			break;
	}
	
	Page page0(PAGESIZE);
	page0.Append(root);
	
	// Put root inside the page List
	m_lPageList.push_back(page0);
	
	Page page1(PAGESIZE);
	// put an empty page inside the page list
	m_lPageList.push_back(page1);


}


BPlusTree:: ~BPlusTree ()
{
	//create and write out the info file
	
	//close open bplus file
	m_oWhereILive.Close();
}


int BPlusTree:: Create (char *fName, Type keyType)
{
	m_oWhereILive.Open(0, fName);
	
	m_iHeight = 1;
	m_iNumPages = 2;
	m_iRootLocation = 0;
	
	//Create root record
	IndexRecord root;
	
	switch ( keyType )
	{
		case Int:
		{
			char buf[ sizeof(int)];
			int neginf = -32767;
			sprintf( buf, "%d", neginf );
			root.Load( buf, sizeof(int), 1);
			break;
		}
		case Double:
		{
			char buf[ sizeof(double)];
			double neginf = -1e309;
			sprintf( buf, "%f", neginf );
			root.Load( buf, sizeof(double), 1);
			break;
		}
		case String:
		{
			char* buf = NULL;
			root.Load( buf, sizeof(char*), 1);
			break;
		}
		default:
			cout<<"default:"<<__LINE__<<endl;
			break;
	}
	
	Page page0(PAGESIZE);
	page0.Append(root);
	
	// Put root inside the page List
	m_lPageList.push_back(page0);
	
	Page page1(PAGESIZE);
	// put an empty page inside the page list
	m_lPageList.push_back(page1);
	
	return 1;

}
